package com.yunhe.authority.service.authority.impl;

import com.github.stuxuhai.jpinyin.PinyinException;
import com.github.stuxuhai.jpinyin.PinyinHelper;
import com.yunhe.authority.domain.authority.*;
import com.yunhe.authority.domain.base.Area;
import com.yunhe.authority.domain.base.FirmType;
import com.yunhe.authority.repository.authority.FirmRepository;
import com.yunhe.authority.repository.authority.MenuRepository;
import com.yunhe.authority.repository.authority.ResourceTreeRepository;
import com.yunhe.authority.service.authority.FirmService;
import com.yunhe.authority.service.authority.HomePageService;
import com.yunhe.authority.service.base.AreaService;
import com.yunhe.authority.service.base.FirmTypeService;
import com.yunhe.authority.service.base.SerialNumService;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.exception.DatabaseProcessException;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.exception.UniqueConstraintsException;
import com.yunhe.common.model.DomainList;
import com.yunhe.common.util.DateTimeUtils;
import com.yunhe.common.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 单位Service
 * @author liuronglei
 */
@Service
public class FirmServiceImpl implements FirmService {
    @Autowired
    private FirmRepository firmRepository;
    @Autowired
    private ResourceTreeRepository resourceTreeRepository;
    @Autowired
    private AreaService areaService;
    @Autowired
    private MenuRepository menuRepository;
    @Autowired
    private FirmTypeService firmTypeService;
    @Autowired
    private HomePageService homePageService;

    @Autowired
    private SerialNumService serialNumService;

    /**
     * 单位对象处理和判断
     * @param firm 单位对象
     */
    private void processBeforeSave(Firm firm)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
//        //地区是否为空
//        HomePage homePage = new HomePage();
//        if (firm.getHomePage() != null && firm.getHomePage().getId() != null && firm.getHomePage().getId() > 0) {
//            homePage = homePageService.findByHomePageId(firm.getHomePage().getId());
//        }
//        Long firmTypeId = 0L;
//        if (firm.getFirmType() != null) {
//            firmTypeId = firm.getFirmType().getId();
//        }
//        //绑定所属单位类型
//        FirmType firmType = null;
//        if (firmTypeId == -1) {
//            firm.setFirmType(null);
//        } else {
//            firmType = firmTypeService.findByFirmTypeId(firmTypeId);
//        }
//        Long areaId = firm.getArea().getId();
//        //绑定所属地区
//        Area area = null;
//        if (areaId == -1) {
//            firm.setArea(null);
//        }  else  {
//            area = areaService.findByAreaId(areaId);
//        }
        //判断单位代码、单位名称是否为空
        if (StringUtil.isEmpty(firm.getEnterpriseFullName())) {
            throw new ArgumentErrorException("企业全称不能为空");
        }
//        //判断单位代码是否已存在
//        Firm firmByCode = this.findByCode(firm.getCode());
//        if (firmByCode != null) {
//            if (firm.getId() == null || firmByCode.getId().longValue() != firm.getId().longValue()) {
//                throw new UniqueConstraintsException("该单位代码已存在");
//            }
//        }
//        //判断单位编号是否已存在
//        Firm firmByName = this.findByName(firm.getName());
//        if (firmByName != null) {
//            if (firm.getId() == null || firmByName.getId().longValue() != firm.getId().longValue()) {
//                throw new UniqueConstraintsException("该单位编号已存在");
//            }
//        }
//        //绑定所属首页
//        if (homePage != null && homePage.getId() != null) {
//            firm.setHomePage(homePage);
//        } else {
//            firm.setHomePage(null);
//        }
//        if (firmTypeId > 0 && firmType == null) {
//            throw new ObjectNotFoundException("找不到所属单位类型");
//        } else {
//            firm.setFirmType(firmType);
//        }
//        if (areaId != -1 && area == null) {
//            throw new ObjectNotFoundException("找不到所属地区");
//        } else {
//            firm.setArea(area);
//        }
    }

    /**
     * 更新父单位关系（添加到父单位）
     * @param firm 子单位对象
     * @param parentId 父单位ID
     */
    private void updateParent(Firm firm, Long parentId) throws ObjectNotFoundException {
        if (firm != null) {
            firmRepository.unbindParentFirmById(firm.getId());
        }
        if (parentId != null && parentId != -1) {
            Firm parentFirm = findByFirmId(parentId);
            if (parentFirm == null) {
                throw new ObjectNotFoundException("找不到ID为" + parentId + "的父单位");
            }
            firmRepository.bindChildFirmById(parentId, parentFirm.getId());
        }
    }

    /**
     * 更新单位类型
     * @param firmId 单位ID
     * @param firmTypeId 单位类型ID
     */
    private void updateFirmType(Long firmId, Long firmTypeId) throws ObjectNotFoundException {
        if (firmId != null) {
            firmRepository.unbindFirmTypeById(firmId);
        }
        if (firmTypeId != null) {
            FirmType firmType = firmTypeService.findByFirmTypeId(firmTypeId);
            if (firmType == null) {
                throw new ObjectNotFoundException("找不到ID为" + firmTypeId + "的单位类型");
            }
            firmRepository.bindFirmTypeById(firmId, firmTypeId);
        }
    }

    /**
     * 对单位列表进行排序
     * @param firmList 菜单列表
     */
    private void sortFirms(List<Firm> firmList) {
        if (firmList != null && firmList.size() > 0) {
            Collections.sort(firmList);
            for (Firm firm : firmList) {
                if (firm.getChildren() != null && firm.getChildren().size() > 0) {
                    sortFirms(firm.getChildren());
                }
            }
        }
    }

    /**
     * 移除重复的孩子单位
     * @param list 单位列表
     */
    private void removeRepeatChild(List<Firm> list) {
        if (list != null && list.size() > 0) {
            //保存重复的ID
            Map<Long, Object> repeatIdMap = new HashMap<>();
            //第一次循环，获得所有孩子节点ID
            for (Firm firm : list) {
                List<Firm> children =  firm.getChildren();
                if (children != null && children.size() > 0) {
                    for (Firm child: children) {
                        repeatIdMap.put(child.getId(), null);
                    }
                }
            }
            //根据是否是孩子节点移除元素
            for (int i = list.size() - 1; i >= 0; i--) {
                Firm firm = list.get(i);
                if (repeatIdMap.containsKey(firm.getId())) {
                    list.remove(i);
                }
            }
        }
    }

    /**
     * 新增单位
     * @param firm 单位对象
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    public Firm createFirm(Firm firm)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException, PinyinException {
        firm.setId(null);
        //生成对应的项目编号
        if("2".equals(firm.getSystem())){
            String yq = serialNumService.generateSerialNumberByModelCode("yq");
            firm.setName(yq);
        }else if("3".equals(firm.getSystem())){
            String yq = serialNumService.generateSerialNumberByModelCode("jq");
            firm.setName(yq);
        }
        firm.setSn(PinyinHelper.getShortPinyin(firm.getEnterpriseFullName()).toUpperCase());
        firm.setCreateTime(DateTimeUtils.format(DateTimeUtils.PATTERN.DATETIME.value(),new Date()));
        //firm.setRoot(parentId == null);
        processBeforeSave(firm);
        Firm newFirm = firmRepository.save(firm);
        //绑定父单位关系
//        if (parentId != null) {
//            updateParent(newFirm, parentId);
//        }
        //绑定单位类型
//        if (firm.getFirmType() != null) {
//            updateFirmType(newFirm.getId(), firm.getFirmType().getId());
//        }
        return newFirm;
    }

    /**
     * 删除单位
     * @param firmId 单位对象ID
     */
    @Override
    @Transactional
    public void deleteFirm(Long firmId) {
        firmRepository.deleteById(firmId);
    }

    /**
     * 更新单位（更新全部字段）
     * @param firm 单位对象
     * @param parentId 父单位ID
     */
    @Override
    @Transactional
    public Firm updateFirm(Firm firm, Long parentId)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        boolean exists = firm.getId() != null && firmRepository.existsById(firm.getId());
        if (!exists) {
            throw new ObjectNotFoundException("找不到ID为" + firm.getId() + "的单位");
        }
        firm.setRoot(parentId == null);
        processBeforeSave(firm);
        //新增单位
        Firm newFirm = firmRepository.save(firm);
        //绑定父单位关系
        if (parentId != null) {
            updateParent(newFirm, parentId);
        }
        return newFirm;
    }

    /**
     * 更新单位（更新指定字段）
     * @param firmId 单位ID
     * @param parentId 父单位ID
     * @param code 单位代码
     * @param name 单位编号
     * @param title 单位名称
     * @param systemTitle 系统标题
     * @param sn 排序
     * @param logAndLat 经纬度
     * @param activity 是否可用
     * @param root 是否为根节点
     */
    @Override
    @Transactional
    public Firm updateFirm(Long firmId,
                           Long parentId,
                           Long code,
                           String name,
                           String title,
                           String systemTitle,
                           String sn,
                           String logAndLat,
                           Long homePageId,
                           Long firmTypeId,
                           Long areaId,
                           Boolean activity,
                           Boolean root)
            throws ArgumentErrorException, ObjectNotFoundException, UniqueConstraintsException {
        Firm firm = this.findByFirmId(firmId);
        if (firm == null) {
            throw new ObjectNotFoundException("找不到ID为" + firmId + "的单位");
        }
        Optional.ofNullable(code).ifPresent(firm::setCode);
        Optional.ofNullable(name).ifPresent(firm::setName);
        Optional.ofNullable(title).ifPresent(firm::setTitle);
        Optional.ofNullable(systemTitle).ifPresent(firm::setSystemTitle);
        Optional.ofNullable(sn).ifPresent(firm::setSn);
        //Optional.ofNullable(activity).ifPresent(firm::setActivity);
        Optional.ofNullable(root).ifPresent(firm::setRoot);
        if (StringUtils.isNotEmpty(logAndLat)) {
            if ("-1".equals(logAndLat)) {
                firm.setLogAndLat(null);
            } else {
                firm.setLogAndLat(logAndLat);
            }
        }
        if (homePageId != null) {
            HomePage homePage = new HomePage();
            homePage.setId(homePageId);
            firm.setHomePage(homePage);
        }
        if (firmTypeId != null) {
            FirmType firmType = new FirmType();
            firmType.setId(firmTypeId);
            firm.setFirmType(firmType);
        }
        if (areaId != null) {
            Area area = new Area();
            area.setId(areaId);
            firm.setArea(area);
        }
        processBeforeSave(firm);
        Firm newFirm = firmRepository.save(firm);
        //绑定父单位关系
        if (parentId != null && parentId > 0) {
            updateParent(newFirm, parentId);
        } else {
            updateParent(newFirm, null);
        }
        return newFirm;
    }

    /**
     * 更新单位类型
     * @param id 单位ID
     * @param firmTypeId 单位类型ID
     */
    @Override
    public void updateFirmTypeById(Long id, Long firmTypeId) throws ObjectNotFoundException {
        updateFirmType(id, firmTypeId);
    }

    /**
     * 更新首页绑定
     * @param id 单位ID
     * @param homePageId 首页对象ID
     */
    @Override
    @Transactional
    public void updateHomePage(Long id, Long homePageId)
            throws ObjectNotFoundException {
        Firm firm = this.findByFirmId(id);
        if (firm == null) {
            throw new ObjectNotFoundException("找不到要修改的单位");
        }
        HomePage homePage = homePageService.findByHomePageId(homePageId);
        if (homePage == null) {
            throw new ObjectNotFoundException("找不到要绑定的首页");
        }
        firm.setHomePage(homePage);
        firmRepository.save(firm);
    }

    /**
     * 根据单位ID获得单位
     * @param id 单位ID
     */
    @Override
    public Firm findByFirmId(Long id) {
//        Firm firm = firmRepository.findOne(id);
        Optional<Firm> firmOpt = firmRepository.findById(id);
        Firm firm = null;
        if (firmOpt.isPresent()) {
            firm = firmOpt.get();
            if (firm.getChildren() != null && firm.getChildren().size() > 0) {
                sortFirms(firm.getChildren());
            }
        }
        return firm;
    }

    /**
     * 根据单位编号获得单位
     * @param name 单位编号
     */
    @Override
    public Firm findByName(String name) {
        return firmRepository.findByName(name);
    }

    /**
     * 根据单位代码获得单位
     * @param code 单位代码
     */
    @Override
    public Firm findByCode(Long code) {
        return firmRepository.findByCode(code);
    }

    /**
     * 根据条件获得单位列表
     */
    @Override
    public Iterable<Firm> findFirms() {
        List<Firm> results = (List<Firm>)firmRepository.findFirms();
        //这种查询有一个问题，会将孩子节点也一并放入List中
        //需要将孩子节点从List中移除
        removeRepeatChild(results);
        sortFirms(results);
        return results;
    }

    /**
     * 单位绑定资源
     * @param firmId 单位ID
     * @param type 资源类型
     * @param resourceId 资源ID
     */
    @Override
    @Transactional
    public void bindResource(Long firmId, String type, Long resourceId) {
        resourceTreeRepository.bindResource(firmId, type, resourceId);
    }

    /**
     * 解绑菜单
     * @param firmId 单位ID
     * @param resourceId 资源ID
     */
    @Override
    @Transactional
    public void unbindResource(Long firmId, Long resourceId) {
        resourceTreeRepository.unbindResource(firmId, resourceId);
    }

    /**
     * 批量更新菜单绑定
     * @param firmId 单位ID
     * @param domainList 资源列表
     */
    @Override
    @Transactional
    public void updateResource(Long firmId, DomainList<ResourceTree> domainList)
            throws DatabaseProcessException {
        //先解绑
        resourceTreeRepository.unbindAllResources(firmId);
        //再绑定
        List<ResourceTree> list = domainList.getList();
        if (list != null && list.size() > 0) {
            for (ResourceTree resourceTree : list) {
                resourceTreeRepository.bindResource(firmId, resourceTree.getType(), resourceTree.getId());
            }
        }
    }

    /**
     * 根据单位ID获得资源树
     * @param firmId 单位ID
     * @param typeList 类型列表
     */
    @Override
    public Iterable<ResourceTree> findResourceTreeByFirmId(Long firmId, List<String> typeList) {
        if (typeList != null && typeList.size() > 0) {
            return resourceTreeRepository.getResourceByFirmIdAndType(firmId, typeList);
        } else {
            return resourceTreeRepository.getResourceByFirmId(firmId);
        }
    }

    /**
     * 根据单位ID获得单位代码
     * @param firmId 单位ID
     */
    @Override
    public Long getFirmCodeById(Long firmId) throws ObjectNotFoundException {
        Long firmCode = null;
        if (firmId != null) {
            Firm firm = findByFirmId(firmId);
            if (firm == null) {
                return null;
                //throw new ObjectNotFoundException("找不到单位ID为" + firmId + "的单位");
            } else {
                firmCode = firm.getCode();
            }
        }
        return firmCode;
    }

    /**
     * 根据单位ID获得单位编号
     * @param firmId 单位ID
     */
    @Override
    public String getFirmNameById(Long firmId) throws ObjectNotFoundException {
        String firmName = null;
        if (firmId != null) {
            Firm firm = findByFirmId(firmId);
            if (firm == null) {
                throw new ObjectNotFoundException("找不到单位ID为" + firmId + "的单位");
            } else {
                firmName = firm.getName();
            }
        }
        return firmName;
    }

    /**
     * 获得有单位关联的地区对象
     */
    @Override
    public Iterable<Area> findFirmAreas() {
        return areaService.findFirmAreas();
    }

    /**
     * 根据单位代码获得单位关联的地区对象
     * @param code 单位代码
     */
    @Override
    public Area findAreaByCode(Long code) {
        return areaService.findFirmArea(code);
    }

    /**
     *根据单位获取所属地区
     * @param firmId 单位ID
     */
    @Override
    public Iterable<Area> findAreaByFirmId(Long firmId){
        return areaService.findAreaByFirmId(firmId);
    }

    /**
     * 更新单位关联的地区对象
     *  @param areaId 地区ID
     *  @param id 单位ID
     */
    @Override
    @Transactional
    public void updateArea(Long id,Long areaId)
            throws ObjectNotFoundException {
        Firm firm = this.findByFirmId(id);
        if (firm == null) {
            throw new ObjectNotFoundException("找不到要修改的单位");
        }
        Area area  = areaService.findByAreaId(areaId);
        if (area == null) {
            throw new ObjectNotFoundException("找不到要关联的地区");
        }
        firm.setArea(area);
        firmRepository.save(firm);
    }

    /**
     * 单位绑定菜单
     * @param firmId 单位ID
     * @param menuId 菜单ID
     */
    @Override
    @Transactional
    public void bindMenu(Long firmId, Long menuId)
            throws DatabaseProcessException {
        firmRepository.bindMenu(firmId, menuId);
    }

    /**
     * 单位绑定菜单
     * @param firmId 单位ID
     * @param menuId 菜单ID
     */
    @Override
    @Transactional
    public void bindAppMenu(Long firmId, Long menuId)
            throws DatabaseProcessException {
        firmRepository.bindAppMenu(firmId, menuId);
    }

    /**
     * 解绑菜单
     * @param firmId 单位ID
     * @param menuId 菜单ID
     */
    @Override
    @Transactional
    public void unbindMenu(Long firmId, Long menuId) {
        firmRepository.unbindMenu(firmId, menuId);
    }

    /**
     * 批量更新菜单绑定
     * @param firmId 单位ID
     * @param menuIdList 菜单ID列表
     */
    @Override
    @Transactional
    public void updateMenu(Long firmId, List<Long> menuIdList)
            throws DatabaseProcessException {
        //先解绑
        firmRepository.unbindAllMenus(firmId);
        //再绑定
        if (menuIdList != null && menuIdList.size() > 0) {
            //for (Long menuId : menuIdList) {
            //    firmRepository.bindMenu(firmId, menuId);
            //}
            firmRepository.bindMenus(firmId, menuIdList);
        }
    }

    /**
     * 根据单位ID获得菜单列表
     * @param firmId 角色ID
     */
    @Override
    public Iterable<Menu> findMenusByFirmId(Long firmId) {
        return menuRepository.findMenusByFirmId(firmId);
    }

    /**
     * 根据单位获得单位类型
     * @param id ID
     */
    @Override
    public FirmType findFirmTypeByFirmId(Long id) {
        return firmRepository.findFirmTypeByFirmId(id);
    }

    /**
     * 根据单位类型获得单位
     * @param firmTypeId 单位类型ID
     */
    @Override
    public Iterable<Firm> findFirmsByFirmTypeId(Long firmTypeId) {
        return firmRepository.findFirmsByFirmTypeId(firmTypeId);
    }

    /**
     * 获得单位绑定的首页
     * @param id 单位ID
     */
    @Override
    public HomePage findHomePageByFirmId(Long id) {
        return homePageService.findHomePageByFirmId(id);
    }

//    public Iterable<Dev> getDevsByFirm(Long firmCode) {
//        return firmRepository.getDevsByFirm(firmCode);
//    }

    /**
     * 根据设备ID找单位
     * @param devId 设备ID
     */
    @Override
    public Iterable<Firm> findFirmByDevId(Long devId) {
        return firmRepository.findFirmByDevId(devId);
    }

    /**
     * 根据电站ID查找所属单位
     * @param stationId 电站ID
     */
    @Override
    public Firm findFirmByStationId(Long stationId) {
        return firmRepository.findFirmByStationId(stationId);
    }

    /**
     * 绑定单位拥有的电站
     * @param id 单位ID
     * @param stationId 电站ID
     */
    @Override
    public void bindStation(Long id, Long stationId) {
        firmRepository.bindStation(id, stationId);
    }

    /**
     * 解绑单位拥有的电站
     * @param id 单位ID
     * @param stationId 电站ID
     */
    @Override
    public void unbindStation(Long id, Long stationId) {
        firmRepository.unbindStation(id, stationId);
    }

    /**
     * 解绑单位下所有电站
     * @param id 单位ID
     */
    private void unbindAllStations(Long id) {
        firmRepository.unbindAllStations(id);
    }

    /**
     * 批量更新电站绑定
     * @param id 单位ID
     * @param domainList 电站列表
     */
    @Override
    @Transactional
    public void updateStation(Long id, DomainList<Station> domainList) {
        //先解绑
        unbindAllStations(id);
        //再绑定
        List<Station> list = domainList.getList();
        if (list != null && list.size() > 0) {
            for (Station station : list) {
                bindStation(id, station.getId());
            }
        }
    }

    @Override
    public Firm findFirmByDevCode(Long devCode) {
        return firmRepository.findFirmByDevCode(devCode);
    }

    @Override
    public Firm findByStationCode(Long stationCode) {
        return firmRepository.findByStationCode(stationCode);
    }

    @Override
    public Iterable<Firm> findAll() {
        return firmRepository.findAll();
    }

    @Override
    public void unbindFirmStaticData(Long fsdId, Long id) {
        firmRepository.unbindFirmStaticData(fsdId,id);
    }

    @Override
    public void bindFirmStaticData(Long fsdId, Long id) {
        firmRepository.bindFirmStaticData(fsdId,id);
    }

    @Override
    public Iterable<Firm> findByRoleIds(List<Long> roleIds) {
        return firmRepository.findFirmsByRoleIds(roleIds);
    }

    @Override
    public Iterable<Firm> findAllFirms() {
        return firmRepository.findAllFirms();
    }

    @Override
    public Iterable<Firm> findBySystem(String code) {
        return firmRepository.findBySystem(code);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    public Firm updateFirm(Long id,Project project) throws ObjectNotFoundException, UniqueConstraintsException, ArgumentErrorException {
        Firm firm = this.findByFirmId(id);
        if (firm == null) {
            throw new ObjectNotFoundException("找不到ID为" + id + "的单位");
        }
        Optional.ofNullable(project.getEnterpriseFullName()).ifPresent(firm::setEnterpriseFullName);
        Optional.ofNullable(project.getFormerName()).ifPresent(firm::setFormerName);
        Optional.ofNullable(project.getCategory()).ifPresent(firm::setCategory);
        Optional.ofNullable(project.getOperatingPeriod()).ifPresent(firm::setOperatingPeriod);
        Optional.ofNullable(project.getPhone()).ifPresent(firm::setPhone);
        Optional.ofNullable(project.getContactTitle()).ifPresent(firm::setContactTitle);
        Optional.ofNullable(project.getContactPerson()).ifPresent(firm::setContactPerson);
        Optional.ofNullable(project.getRegisteredCapital()).ifPresent(firm::setRegisteredCapital);
        Optional.ofNullable(project.getCorporateLogo()).ifPresent(firm::setCorporateLogo);
        Optional.ofNullable(project.getCorporateLogoThumbnail()).ifPresent(firm::setCorporateLogoThumbnail);
        Optional.ofNullable(project.getBusinessRegisteredAddress()).ifPresent(firm::setBusinessRegisteredAddress);
        Optional.ofNullable(project.getAddress()).ifPresent(firm::setAddress);
        processBeforeSave(firm);
        Firm newFirm = firmRepository.save(firm);
        return newFirm;
    }

    @Override
    public Firm findByStationId(Long stationId) {
        return firmRepository.findByStationId(stationId);
    }
}
